package com.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * CAS  compareAndSet  比较并交换   ,是一种自旋锁
 * 比较当前工作内存中的值和主内存中的值，如果是期望值，就执行操作；如果不是就一直循环
 * 缺点
 * 1、循环会耗时
 * 2、一次性只能保证一个共享变量的原子性
 * 3、存在ABA问题（狸猫换太子），拿到的值不一定是原来的值；  AtomicStampedReference解决ABA问题（类似于加了版本号）
 */
public class CASDemo {

    public static void main(String[] args) throws Exception {


//        AtomicInteger atomicInteger = new AtomicInteger(2020);
//
//        //与期望值比较，达到就更新
//        System.out.println(atomicInteger.compareAndSet(2020, 2021));
//        System.out.println(atomicInteger.get());
//
//        System.out.println(atomicInteger.compareAndSet(2020, 2029));
//        System.out.println(atomicInteger.get());

        //AtomicStampedReference解决ABA问题（类似于加了版本号）
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(1, 1);

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp(); //获得版本号
            System.out.println("a1=>" + stamp);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicStampedReference.compareAndSet(1, 2, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a=>" + atomicStampedReference.getStamp());

            System.out.println(atomicStampedReference.compareAndSet(2, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp()));

            System.out.println("a=>" + atomicStampedReference.getStamp());

        }, "a").start();


        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp(); //获得版本号
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicStampedReference.compareAndSet(1, 6, stamp, atomicStampedReference.getStamp() + 1));
            System.out.println("b1=>" + atomicStampedReference.getStamp());
        }, "b").start();

    }
}
